home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / quicktime / quicktime vr / vrscript / common files / urlutilities.c < prev    next >
Encoding:
Text File  |  2000-06-23  |  26.2 KB  |  1,044 lines

  1. //////////
  2. //
  3. //    File:        URLUtilities.c
  4. //
  5. //    Contains:    Some utilities for working with URLs.
  6. //                All utilities start with the prefix "URLUtils_".
  7. //
  8. //    Written by:    Tim Monroe
  9. //
  10. //    Copyright:    © 1998 by Apple Computer, Inc., all rights reserved.
  11. //
  12. //    Change History (most recent first):
  13. //
  14. //       <6>         02/22/99    rtm        added URLUtils_HaveBrowserOpenURL
  15. //       <5>         12/26/98    rtm        added URLUtils_LocationFromFullPath
  16. //       <4>         12/23/98    rtm        added URLUtils_FSSpecToFullNativePath, URLUtils_FSSpecToURL, and
  17. //                                    URLUtils_URLToFSSpec; fixed bug in URLUtils_DecodeString
  18. //       <3>         12/07/98    rtm        modified URLUtils_NewMovieFromURL to take flags and ID parameters;
  19. //                                    added URLUtils_URLToFullNativePath
  20. //       <2>         12/06/98    rtm        more work; finished URLUtils_FullNativePathToURL
  21. //       <1>         12/04/98    rtm        first file
  22. //
  23. //    The structure of URLs assumed in these functions is based on that specified in
  24. //    the Network Working Group RFC 2396 (August 1998) by Tim Berners-Lee (who else?)
  25. //    et al. In addition, I have adopted the terminology used in that document.
  26. //
  27. //    The basic structure of an absolute URL is this:
  28. //
  29. //                        <scheme>://<authority><path>?<query>
  30. //     
  31. //////////
  32.  
  33. // header files
  34.  
  35. #ifndef __URLUtilities__
  36. #include "URLUtilities.h"
  37.  
  38.  
  39. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  40. //
  41. // Syntax utilities.
  42. //
  43. // Use these functions to retrieve the distinguishable parts of a URL.
  44. //
  45. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  46.  
  47. //////////
  48. //
  49. // URLUtils_GetScheme
  50. // Return the scheme portion of the specified (absolute) URL. If that URL is not absolute, return NULL.
  51. //
  52. // The scheme of a URL is the leading portion of a URL. It specifies the protocol to be used to access
  53. // the named resource. RFC 2396 specifies that a scheme begin with an alphabetic character and contain
  54. // only alphanumerics and '+', '-', '.'; we don't check for this yet.
  55. //
  56. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  57. //
  58. //////////
  59.  
  60. char *URLUtils_GetScheme (char *theURL)
  61. {
  62.     char    *myScheme = NULL;
  63.     short    myLength = 0;
  64.     short    myIndex;
  65.     
  66.     // make sure we were passed an absolute URL
  67.     if (!URLUtils_IsAbsoluteURL(theURL))
  68.         return(myScheme);
  69.  
  70.     // find the length of the scheme
  71.     while (theURL[myLength] != kURLSchemeSeparator)
  72.         myLength++;
  73.     
  74.     myScheme = malloc(myLength + 1);
  75.     if (myScheme != NULL) {
  76.         for (myIndex = 0; myIndex < myLength; myIndex++)
  77.             myScheme[myIndex] = URLUtils_ToLowercase(theURL[myIndex]);
  78.             
  79.         myScheme[myLength] = '\0';
  80.     }
  81.     
  82.     return(myScheme);
  83. }
  84.  
  85.  
  86. //////////
  87. //
  88. // URLUtils_GetAuthority
  89. // Return the naming authority portion of the specified (absolute) URL. If that URL is not absolute,
  90. // return NULL.
  91. //
  92. // The authority is preceded by a double slash and is terminated by the following slash, question mark,
  93. // or null character. In some cases, the authority portion of a URL is empty; in those cases, we return
  94. // a non-NULL pointer to an empty string.
  95. //
  96. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  97. //
  98. //////////
  99.  
  100. char *URLUtils_GetAuthority (char *theURL)
  101. {
  102.     char    *myAuthority = NULL;
  103.     char    *myString = NULL;
  104.     short    myLength = 0;
  105.     
  106.     // make sure we were passed an absolute URL
  107.     if (!URLUtils_IsAbsoluteURL(theURL))
  108.         return(myAuthority);
  109.  
  110.     // find the place in theURL where the authority prefix begins
  111.     myString = URLUtils_GetAuthBegin(theURL);
  112.     if (myString != NULL) {
  113.         // get the length of the authority portion
  114.         myLength = strcspn(myString + strlen(kURLAuthPrefix), kURLAuthSuffix);
  115.         
  116.         myAuthority = malloc(myLength + 1);
  117.         if (myAuthority != NULL) {
  118.             strncpy(myAuthority, myString + strlen(kURLAuthPrefix), myLength);
  119.             myAuthority[myLength] = '\0';
  120.         }
  121.     }
  122.  
  123.     return(myAuthority);
  124. }
  125.  
  126.  
  127. //////////
  128. //
  129. // URLUtils_GetPath
  130. // Return the path portion of the specified (absolute) URL. If that URL is not absolute, return NULL.
  131. //
  132. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  133. //
  134. //////////
  135.  
  136. char *URLUtils_GetPath (char *theURL)
  137. {
  138.     char    *myPath = NULL;
  139.     char    *myString = NULL;
  140.     short    myLength = 0;
  141.     
  142.     // make sure we were passed an absolute URL
  143.     if (!URLUtils_IsAbsoluteURL(theURL))
  144.         return(myPath);
  145.  
  146.     // find the place in theURL where the path prefix begins
  147.     myString = URLUtils_GetPathBegin(theURL);
  148.     if (myString != NULL) {
  149.         // get the length of the path portion
  150.         myLength = strcspn(myString, kURLPathSuffix);
  151.         
  152.         myPath = malloc(myLength + 1);
  153.         if (myPath != NULL) {
  154.             strncpy(myPath, myString, myLength);
  155.             myPath[myLength] = '\0';
  156.         }
  157.     }
  158.  
  159.     return(myPath);
  160. }
  161.  
  162.  
  163. //////////
  164. //
  165. // URLUtils_GetQuery
  166. // Return the query portion of the specified (absolute) URL. If that URL is not absolute, return NULL.
  167. //
  168. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  169. //
  170. //////////
  171.  
  172. char *URLUtils_GetQuery (char *theURL)
  173. {
  174.     char    *myQuery = NULL;
  175.     char    *myString = NULL;
  176.     
  177.     // make sure we were passed an absolute URL
  178.     if (!URLUtils_IsAbsoluteURL(theURL))
  179.         return(myQuery);
  180.  
  181.     // find the place in theURL where the query begins
  182.     myString = URLUtils_GetQueryBegin(theURL);
  183.     if (myString != NULL) {
  184.         myQuery = malloc(strlen(myString) + 1);
  185.         if (myQuery != NULL) {
  186.             strcpy(myQuery, myString);
  187.             myQuery[strlen(myString)] = '\0';
  188.         }
  189.     }
  190.  
  191.     return(myQuery);
  192. }
  193.  
  194.  
  195. //////////
  196. //
  197. // URLUtils_GetAuthBegin
  198. // Return a pointer to the beginning of the authority portion of the specified URL.
  199. //
  200. //////////
  201.  
  202. static char *URLUtils_GetAuthBegin (char *theURL)
  203. {
  204.     return(strstr(theURL, kURLAuthPrefix));
  205. }
  206.  
  207.  
  208. //////////
  209. //
  210. // URLUtils_GetPathBegin
  211. // Return a pointer to the beginning of the path portion of the specified URL.
  212. //
  213. //////////
  214.  
  215. static char *URLUtils_GetPathBegin (char *theURL)
  216. {
  217.     char    *myString = NULL;
  218.     short    myLength = 0;
  219.     
  220.     myString = URLUtils_GetAuthBegin(theURL);
  221.     if (myString != NULL) {
  222.         // get the length of the authority portion
  223.         myLength = strcspn(myString + strlen(kURLAuthPrefix), kURLAuthSuffix);
  224.         
  225.         // determine the beginning of the path portion
  226.         myString += (myLength + strlen(kURLAuthPrefix));
  227.     }
  228.     
  229.     return(myString);
  230. }
  231.  
  232.  
  233. //////////
  234. //
  235. // URLUtils_GetQueryBegin
  236. // Return a pointer to the beginning of the query portion of the specified URL.
  237. //
  238. //////////
  239.  
  240. static char *URLUtils_GetQueryBegin (char *theURL)
  241. {
  242.     char    *myString = NULL;
  243.     
  244.     myString = strchr(theURL, kURLQuerySeparator);
  245.     if (myString != NULL)
  246.         myString++;            // to skip over the query separator
  247.     
  248.     return(myString);
  249. }
  250.  
  251.  
  252. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  253. //
  254. // FSSpec/URL/Pathname conversion utilities.
  255. //
  256. // Use these functions to convert among FSSpecs, URLs, and pathnames.
  257. //
  258. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  259.  
  260. //////////
  261. //
  262. // URLUtils_FullNativePathToURL 
  263. // Convert a full native pathname into a local file URL.
  264. //
  265. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  266. //
  267. //////////
  268.  
  269. char *URLUtils_FullNativePathToURL (char *thePath)
  270. {
  271.     char        *myURL = NULL;    
  272.     char        *myScratchStr = NULL;    
  273.     char        *myEncodedStr = NULL;    
  274.     short        myIndex;
  275.     
  276.     if (thePath == NULL)
  277.         goto bail;
  278.  
  279.     //////////
  280.     //
  281.     // transform thePath as required by the target operating system
  282.     //
  283.     // on MacOS, a full pathname is of the form <vol>:<dir>:...:<dir>:<name>
  284.     // to convert this into a form appropriate to URLs, we need only convert
  285.     // the colon (:) into the URL separator (/)
  286.     //
  287.     // on Windows, a full pathname has the form <vol>:\<dir>\<dir>\...\<name>
  288.     // to convert this into a form appropriate to URLs, we need to convert
  289.     // the colon (:) into '|' and the backslash (\) into the URL separator (/)
  290.     //
  291.     //////////
  292.     
  293.     myScratchStr = malloc(strlen(thePath) + 1);
  294.     if (myScratchStr == NULL)
  295.         goto bail;
  296.     
  297.     for (myIndex = 0; myIndex <= strlen(thePath); myIndex++)
  298.         if (thePath[myIndex] == kFilePathSeparator)
  299.             myScratchStr[myIndex] = kURLPathSeparator;
  300. #if TARGET_OS_WIN32
  301.         else if (thePath[myIndex] == kWinVolumeNameChar)
  302.             myScratchStr[myIndex] = kURLVolumeNameChar;
  303. #endif
  304.         else
  305.             myScratchStr[myIndex] = thePath[myIndex];
  306.  
  307.     //////////
  308.     //
  309.     // encode the transformed string
  310.     //
  311.     //////////
  312.     
  313.     myEncodedStr = URLUtils_EncodeString(myScratchStr);
  314.     if (myEncodedStr == NULL)
  315.         goto bail;
  316.  
  317.     myURL = malloc(strlen(myEncodedStr) + strlen(kFilePrefix) + strlen(kLocalhostAuth) + strlen("/") + 1);
  318.     if (myURL == NULL)
  319.         goto bail;
  320.         
  321.     //////////
  322.     //
  323.     // prepend the appropriate URL head
  324.     //
  325.     //////////
  326.     
  327.     myURL[0] = '\0';
  328.     strcat(myURL, kFilePrefix);
  329.     strcat(myURL, kLocalhostAuth);
  330.     strcat(myURL, "/");
  331.  
  332.     //////////
  333.     //
  334.     // append the converted and encoded path name to the URL head
  335.     //
  336.     //////////
  337.     
  338.     strcat(myURL, myEncodedStr);
  339.     
  340. bail:
  341.     if (myScratchStr != NULL)
  342.         free(myScratchStr);
  343.         
  344.     if (myEncodedStr != NULL)
  345.         free(myEncodedStr);
  346.         
  347.     return(myURL);
  348. }
  349.  
  350.  
  351. //////////
  352. //
  353. // URLUtils_URLToFullNativePath 
  354. // Convert a local file URL into a full native pathname.
  355. //
  356. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  357. //
  358. //////////
  359.  
  360. char *URLUtils_URLToFullNativePath (char *theURL)
  361. {
  362.     char        *myScratchStr = NULL;    
  363.     char        *myDecodedStr = NULL;    
  364.     short        myIndex;
  365.  
  366.     if (theURL == NULL)
  367.         goto bail;
  368.  
  369.     // make sure we were passed a file URL; the URL must begin with the file prefix
  370.     myScratchStr = strstr(theURL, kFilePrefix);
  371.     if ((myScratchStr == NULL) || (myScratchStr != theURL))
  372.         goto bail;
  373.     
  374.     // strip off the URL head
  375.     myScratchStr += strlen(kFilePrefix);
  376.     
  377.     // strip off the authority portion, if it's non-empty
  378.     if (strstr(theURL, kLocalhostStr) == myScratchStr)
  379.         myScratchStr += strlen(kLocalhostStr);
  380.         
  381.     // strip off the authority portion, if it's just '/'
  382.     if (myScratchStr[0] == kURLPathSeparator)
  383.         myScratchStr++;
  384.     
  385.     // decode the path string
  386.     myDecodedStr = URLUtils_DecodeString(myScratchStr);
  387.     if (myDecodedStr == NULL)
  388.         goto bail;
  389.  
  390.     // transform the decoded path as required by the target operating system
  391.     for (myIndex = 0; myIndex <= strlen(myDecodedStr); myIndex++)
  392.         if (myDecodedStr[myIndex] == kURLPathSeparator)
  393.             myDecodedStr[myIndex] = kFilePathSeparator;
  394. #if TARGET_OS_WIN32
  395.         else if (myDecodedStr[myIndex] == kURLVolumeNameChar)
  396.             myDecodedStr[myIndex] = kWinVolumeNameChar;
  397. #endif
  398.  
  399. bail:
  400.     return(myDecodedStr);
  401. }
  402.  
  403.  
  404. //////////
  405. //
  406. // URLUtils_FullNativePathToFSSpec
  407. // Convert a full native pathname into an FSSpec.
  408. //
  409. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  410. //
  411. //////////
  412.  
  413. FSSpecPtr URLUtils_FullNativePathToFSSpec (char *thePath)
  414. {
  415.     FSSpecPtr        myFSSpecPtr = malloc(sizeof(FSSpec));
  416.     
  417.     if (myFSSpecPtr == NULL)
  418.         return(myFSSpecPtr);
  419.         
  420.     if (strlen(thePath) < 255)
  421.         FSMakeFSSpec(0, 0L, c2pstr(thePath), myFSSpecPtr);
  422.     else
  423.         URLUtils_LocationFromFullPath(strlen(thePath), thePath, myFSSpecPtr);
  424.         
  425.     return(myFSSpecPtr);
  426. }
  427.  
  428.  
  429. //////////
  430. //
  431. // URLUtils_FSSpecToFullNativePath
  432. // Convert an FSSpec into a full native pathname.
  433. //
  434. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  435. //
  436. //////////
  437.  
  438. char *URLUtils_FSSpecToFullNativePath (const FSSpecPtr theFSSpecPtr)
  439. {
  440.     char            *myPathName = NULL;
  441. #if TARGET_OS_MAC    
  442.     Handle            myHandle = NULL;
  443.     short            myLength = 0;
  444. #endif
  445.  
  446.     if (theFSSpecPtr == NULL)
  447.         goto bail;
  448.  
  449.     myPathName = malloc(MAX_PATH);
  450.     if (myPathName == NULL)
  451.         goto bail;
  452.  
  453. #if TARGET_OS_WIN32
  454.     // on Windows, this is easy (thanks to those hardworking QuickTime engineers)
  455.     FSSpecToNativePathName(theFSSpecPtr, myPathName, MAX_PATH, kFullNativePath);    
  456. #elif TARGET_OS_MAC    
  457.     // on Macintosh, this is easy (thanks to that hardworking Jim Luther)
  458.     URLUtils_FSpecGetFullPath(theFSSpecPtr, &myLength, &myHandle);
  459.     BlockMove(*myHandle, myPathName, myLength);
  460.     myPathName[myLength] = '\0';
  461. #endif
  462.  
  463. bail:
  464.     return(myPathName);
  465. }
  466.  
  467.  
  468. //////////
  469. //
  470. // URLUtils_FSSpecToURL
  471. // Convert an FSSpec into a local file URL.
  472. //
  473. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  474. //
  475. //////////
  476.  
  477. char *URLUtils_FSSpecToURL (const FSSpecPtr theFSSpecPtr)
  478. {
  479.     char        *myPathName = NULL;
  480.     char        *myURL = NULL;
  481.     
  482.     myPathName = URLUtils_FSSpecToFullNativePath(theFSSpecPtr);
  483.     myURL = URLUtils_FullNativePathToURL(myPathName);
  484.     
  485.     free(myPathName);
  486.     return(myURL);
  487. }
  488.  
  489.  
  490. //////////
  491. //
  492. // URLUtils_URLToFSSpec
  493. // Convert a local file URL into an FSSpec.
  494. //
  495. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  496. //
  497. //////////
  498.  
  499. FSSpecPtr URLUtils_URLToFSSpec (char *theURL)
  500. {
  501.     char        *myPathName = NULL;
  502.     FSSpecPtr    myFSSpecPtr = malloc(sizeof(FSSpec));
  503.     
  504.     if (myFSSpecPtr == NULL)
  505.         return(myFSSpecPtr);
  506.  
  507.     myPathName = URLUtils_URLToFullNativePath(theURL);
  508.     myFSSpecPtr = URLUtils_FullNativePathToFSSpec(myPathName);
  509.     
  510.     free(myPathName);
  511.     return(myFSSpecPtr);
  512. }
  513.  
  514.  
  515. //////////
  516. //
  517. // URLUtils_FSpecGetFullPath 
  518. // Get a full path name from an FSSpec.
  519. //
  520. // This is straight out of MoreFiles 1.4 by Jim Luther; the only thing I did was to change the name
  521. // and make the coding style consistent with the rest of this file.
  522. //
  523. // NOTE: This function is MACINTOSH ONLY.
  524. //
  525. //////////
  526.  
  527. static OSErr URLUtils_FSpecGetFullPath (const FSSpecPtr theFSSpecPtr, short *theFullPathLength, Handle *theFullPath)
  528. {
  529.     FSSpec            myTempSpec;
  530.     CInfoPBRec        myPBRec;
  531.     OSErr            myErr = noErr;
  532.     
  533.     *theFullPathLength = 0;
  534.     *theFullPath = NULL;
  535.     
  536.     // make a copy of the input FSSpec that can be modified
  537.     BlockMoveData(theFSSpecPtr, &myTempSpec, sizeof(FSSpec));
  538.     
  539.     if (myTempSpec.parID == fsRtParID) {
  540.         // the object is a volume; add a colon to make it a full pathname
  541.         ++myTempSpec.name[0];
  542.         myTempSpec.name[myTempSpec.name[0]] = kFilePathSeparator;
  543.         
  544.         // we're done
  545.         myErr = PtrToHand(&myTempSpec.name[1], theFullPath, myTempSpec.name[0]);
  546.     } else {
  547.         // the object isn't a volume; is the object a file or a directory?
  548.         myPBRec.dirInfo.ioNamePtr = myTempSpec.name;
  549.         myPBRec.dirInfo.ioVRefNum = myTempSpec.vRefNum;
  550.         myPBRec.dirInfo.ioDrDirID = myTempSpec.parID;
  551.         myPBRec.dirInfo.ioFDirIndex = 0;
  552.         myErr = PBGetCatInfoSync(&myPBRec);
  553.         if (myErr == noErr) {
  554.             // if the object is a directory, append a colon so full pathname ends with colon
  555.             if ((myPBRec.hFileInfo.ioFlAttrib & ioDirMask) != 0) {
  556.                 ++myTempSpec.name[0];
  557.                 myTempSpec.name[myTempSpec.name[0]] = kFilePathSeparator;
  558.             }
  559.             
  560.             // put the object name in first
  561.             myErr = PtrToHand(&myTempSpec.name[1], theFullPath, myTempSpec.name[0]);
  562.             if (myErr == noErr) {
  563.                 // get the ancestor directory names
  564.                 myPBRec.dirInfo.ioNamePtr = myTempSpec.name;
  565.                 myPBRec.dirInfo.ioVRefNum = myTempSpec.vRefNum;
  566.                 myPBRec.dirInfo.ioDrParID = myTempSpec.parID;
  567.                 
  568.                 // loop until we have an error or find the root directory
  569.                 do {
  570.                     myPBRec.dirInfo.ioFDirIndex = -1;
  571.                     myPBRec.dirInfo.ioDrDirID = myPBRec.dirInfo.ioDrParID;
  572.                     myErr = PBGetCatInfoSync(&myPBRec);
  573.                     if (myErr == noErr) {
  574.                         // append colon to directory name
  575.                         ++myTempSpec.name[0];
  576.                         myTempSpec.name[myTempSpec.name[0]] = kFilePathSeparator;
  577.                         
  578.                         // add directory name to beginning of theFullPath
  579.                         (void) Munger(*theFullPath, 0, NULL, 0, &myTempSpec.name[1], myTempSpec.name[0]);
  580.                         myErr = MemError();
  581.                     }
  582.                 } while ((myErr == noErr) && (myPBRec.dirInfo.ioDrDirID != fsRtDirID));
  583.             }
  584.         }
  585.     }
  586.     if (myErr == noErr) {
  587.         // return the length
  588.         *theFullPathLength = InlineGetHandleSize(*theFullPath);
  589.     } else {
  590.         // dispose of the handle and return NULL and zero length
  591.         if (*theFullPath != NULL)
  592.             DisposeHandle(*theFullPath);
  593.         *theFullPath = NULL;
  594.         *theFullPathLength = 0;
  595.     }
  596.     
  597.     return(myErr);
  598. }
  599.  
  600.  
  601. //////////
  602. //
  603. // URLUtils_LocationFromFullPath 
  604. // Get a full path name from an FSSpec.
  605. //
  606. // This is straight out of MoreFiles 1.4 by Jim Luther; the only thing I did was to change the name
  607. // and make the coding style consistent with the rest of this file.
  608. //
  609. //////////
  610.  
  611. static OSErr URLUtils_LocationFromFullPath (short theFullPathLength, const void *theFullPath, FSSpecPtr theFSSpecPtr)
  612. {
  613.     AliasHandle        myAliasHandle;
  614.     Boolean            myWasChanged;
  615.     Str32            myString;
  616.     OSErr            myErr;
  617.     
  618.     // create a minimal alias from the full pathname
  619.     myString[0] = 0;    // null string to indicate no zone or server name
  620.     myErr = NewAliasMinimalFromFullPath(theFullPathLength, theFullPath, myString, myString, &myAliasHandle);
  621.     if (myErr == noErr) {
  622.         // let the Alias Manager resolve the alias
  623.         myErr = ResolveAlias(NULL, myAliasHandle, theFSSpecPtr, &myWasChanged);
  624.         DisposeHandle((Handle)myAliasHandle);
  625.     }
  626.     
  627.     return(myErr);
  628. }
  629.  
  630.  
  631. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  632. //
  633. // Relative URL utilities.
  634. //
  635. // Use these functions to manage relative URLs.
  636. //
  637. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  638.  
  639. // TO BE PROVIDED
  640.  
  641.  
  642.  
  643. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  644. //
  645. // Movie utilities.
  646. //
  647. // Use these functions to open movies or web pages addressed by URLs.
  648. //
  649. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  650.  
  651. //////////
  652. //
  653. // URLUtils_NewMovieFromURL
  654. // Open the movie file referenced by the specified uniform resource locator (URL).
  655. //
  656. //////////
  657.  
  658. Movie URLUtils_NewMovieFromURL (char *theURL, short theFlags, short *theID)
  659. {
  660.     Movie        myMovie = NULL;
  661.     Handle        myHandle = NULL;
  662.     Size        mySize = 0;
  663.     
  664.     //////////
  665.     //
  666.     // copy the specified URL into a handle
  667.     //
  668.     //////////
  669.     
  670.     // get the size of the URL, plus the terminating null byte
  671.     mySize = (Size)strlen(theURL) + 1;
  672.     if (mySize == 0)
  673.         goto bail;
  674.     
  675.     // allocate a new handle
  676.     myHandle = NewHandleClear(mySize);
  677.     if (myHandle == NULL)
  678.         goto bail;
  679.  
  680.     // copy the URL into the handle
  681.     BlockMove(theURL, *myHandle, mySize);
  682.  
  683.     //////////
  684.     //
  685.     // instantiate a movie from the specified URL
  686.     //
  687.     // the data reference that is passed to NewMovieFromDataRef is a handle
  688.     // containing the text of the URL, *with* a terminating null byte; this
  689.     // is an exception to the usual practice with data references (where you
  690.     // need to pass a handle to a handle containing the relevant data)
  691.     //
  692.     //////////
  693.     
  694.     NewMovieFromDataRef(&myMovie, theFlags, theID, myHandle, URLDataHandlerSubType);
  695.  
  696. bail:
  697.     if (myHandle != NULL)
  698.         DisposeHandle(myHandle);
  699.         
  700.     return(myMovie);
  701. }
  702.  
  703.  
  704. //////////
  705. //
  706. // URLUtils_HaveBrowserOpenURL
  707. // Tell the user's default web browser to open the specified uniform resource locator (URL).
  708. //
  709. //////////
  710.  
  711. OSErr URLUtils_HaveBrowserOpenURL (char *theURL)
  712. {
  713.     MovieController        myMC = NULL;
  714.     Handle                myHandle = NULL;
  715.     Size                mySize = 0;
  716.     OSErr                myErr = noErr;
  717.     
  718.     //////////
  719.     //
  720.     // copy the specified URL into a handle
  721.     //
  722.     //////////
  723.     
  724.     // get the size of the URL, plus the terminating null byte
  725.     mySize = (Size)strlen(theURL) + 1;
  726.     if (mySize == 0)
  727.         goto bail;
  728.     
  729.     // allocate a new handle
  730.     myHandle = NewHandleClear(mySize);
  731.     if (myHandle == NULL)
  732.         goto bail;
  733.  
  734.     // copy the URL into the handle
  735.     BlockMove(theURL, *myHandle, mySize);
  736.  
  737.     //////////
  738.     //
  739.     // instantiate a movie controller and send it an mcActionLinkToURL message
  740.     //
  741.     //////////
  742.     
  743.     myErr = OpenADefaultComponent(MovieControllerComponentType, 0, &myMC);
  744.     if (myErr != noErr)
  745.         goto bail;
  746.         
  747.     myErr = MCDoAction(myMC, mcActionLinkToURL, (void *)myHandle);
  748.  
  749. bail:
  750.     if (myHandle != NULL)
  751.         DisposeHandle(myHandle);
  752.         
  753.     if (myMC != NULL)
  754.         CloseComponent(myMC);
  755.         
  756.     return(myErr);
  757. }
  758.  
  759.  
  760. //////////
  761. //
  762. // URLUtils_GetURLBasename
  763. // Return the basename of the specified URL.
  764. //
  765. // The basename of a URL is the portion of the URL following the rightmost URL separator. This function
  766. // is useful for setting window titles of movies opened using the URL data handler to the basename of a
  767. // URL (just like MoviePlayer does).
  768. //
  769. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  770. //
  771. //////////
  772.  
  773. char *URLUtils_GetURLBasename (char *theURL)
  774. {
  775.     char    *myBasename = NULL;
  776.     short    myLength = 0;
  777.     short    myIndex;
  778.  
  779.     // make sure we got a URL passed in
  780.     if (theURL == NULL)
  781.         goto bail;
  782.         
  783.     // get the length of the URL
  784.     myLength = strlen(theURL);
  785.     
  786.     // find the position of the rightmost URL path separator in theURL
  787.     if (strchr(theURL, kURLPathSeparator) != NULL) {
  788.  
  789.         myIndex = myLength - 1;
  790.         while (theURL[myIndex] != kURLPathSeparator)
  791.             myIndex--;
  792.             
  793.         // calculate the length of the basename
  794.         myLength = myLength - myIndex - 1;
  795.  
  796.     } else {
  797.         // there is no rightmost URL path separator in theURL;
  798.         // set myIndex so that myIndex + 1 == 0, for the call to BlockMove below
  799.         myIndex = -1;
  800.     }
  801.     
  802.     // allocate space to hold the string that we return to the caller
  803.     myBasename = malloc(myLength + 1);
  804.     if (myBasename == NULL)
  805.         goto bail;
  806.         
  807.     // copy into myBasename the substring of theURL from myIndex + 1 to the end
  808.     BlockMove(&theURL[myIndex + 1], myBasename, myLength);
  809.     myBasename[myLength] = '\0';
  810.     
  811. bail:    
  812.     return(myBasename);
  813. }
  814.  
  815.  
  816. //////////
  817. //
  818. // URLUtils_IsAbsoluteURL
  819. // Is the specified string an absolute URL?
  820. //
  821. // An absolute URL must begin with an alphabetic character, and it must contain
  822. // the URL scheme separator.
  823. //
  824. //////////
  825.  
  826. Boolean URLUtils_IsAbsoluteURL (char *theURL)
  827. {
  828.     if (theURL == NULL)
  829.         return(false);
  830.         
  831.     if (URLUtils_IsAlphabetic(theURL[0]))
  832.         if (strchr(theURL, kURLSchemeSeparator) != NULL)
  833.             return(true);
  834.  
  835.     return(false);
  836. }
  837.  
  838.  
  839. //////////
  840. //
  841. // URLUtils_IsRelativeURL
  842. // Is the specified string a relative URL?
  843. //
  844. //////////
  845.  
  846. Boolean URLUtils_IsRelativeURL (char *theURL)
  847. {
  848.     return(!URLUtils_IsAbsoluteURL(theURL));
  849. }
  850.  
  851.  
  852. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  853. //
  854. // Character encoding utilities.
  855. //
  856. // Use these functions to encode or decode "escaped" characters within URLs.
  857. //
  858. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  859.  
  860. //////////
  861. //
  862. // URLUtils_IsReservedChar
  863. // Is the specified character a reserved character?
  864. //
  865. //////////
  866.  
  867. static Boolean URLUtils_IsReservedChar (char theChar)
  868. {
  869.     if ((theChar == ';') || (theChar == '/') || (theChar == '?') || (theChar == ':') || (theChar == '@') ||
  870.         (theChar == '&') || (theChar == '=') || (theChar == '+') || (theChar == '$') || (theChar == ','))
  871.         return(true);
  872.  
  873.     return(false);
  874. }
  875.  
  876.  
  877. //////////
  878. //
  879. // URLUtils_IsDelimiterChar
  880. // Is the specified character a delimiter?
  881. //
  882. //////////
  883.  
  884. static Boolean URLUtils_IsDelimiterChar (char theChar)
  885. {
  886.     if ((theChar == '<') || (theChar == '>') || (theChar == '#') || (theChar == '%') || (theChar == '"'))
  887.         return(true);
  888.  
  889.     return(false);
  890. }
  891.  
  892.  
  893. //////////
  894. //
  895. // URLUtils_IsPunctMarkChar
  896. // Is the specified character a punctuation mark or similar symbol?
  897. //
  898. //////////
  899.  
  900. static Boolean URLUtils_IsPunctMarkChar (char theChar)
  901. {
  902.     if ((theChar == '-') || (theChar == '_') || (theChar == '.') || (theChar == '!') || (theChar == '~') ||
  903.         (theChar == '*') || (theChar == '(') || (theChar == ')') || (theChar == '\''))
  904.         return(true);
  905.  
  906.     return(false);
  907. }
  908.  
  909.  
  910. //////////
  911. //
  912. // URLUtils_IsEncodableChar
  913. // Is the specified character a character that should be encoded?
  914. //
  915. //////////
  916.  
  917. static Boolean URLUtils_IsEncodableChar (char theChar)
  918. {
  919.     // all control characters and high-ASCII characters are encodable
  920.     if ((theChar <= 0x1f) || (theChar >= 0x7f))
  921.         return(true);
  922.     
  923.     // the space character is encodable
  924.     if (theChar == 0x20)
  925.         return(true);
  926.     
  927.     // all delimiters are encodable
  928.     if (URLUtils_IsDelimiterChar(theChar))
  929.         return(true);
  930.     
  931.     return(false);
  932. }
  933.  
  934.  
  935. //////////
  936. //
  937. // URLUtils_EncodeString 
  938. // Convert any special characters in the specified string into their encoded versions.
  939. //
  940. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  941. //
  942. //////////
  943.  
  944. static char *URLUtils_EncodeString (char *theString)
  945. {
  946.     char        *myEncodedStr = NULL;    
  947.     char        myChar;
  948.     short        myCount = 0;
  949.     short        myIndex;
  950.  
  951.     if (theString == NULL)
  952.         goto bail;
  953.  
  954.     // count the number of special characters that need converting
  955.     for (myIndex = 0; myIndex < strlen(theString); myIndex++)
  956.         if (URLUtils_IsEncodableChar(theString[myIndex]))
  957.             myCount++;
  958.  
  959.     // allocate a character string of the proper size;
  960.     // each encoded character increases the length of the original string by 2 bytes
  961.     myEncodedStr = malloc(strlen(theString) + (myCount * 2) + 1);
  962.     if (myEncodedStr == NULL)
  963.         goto bail;
  964.  
  965.     // traverse the URL, encoding encodable characters as we go
  966.     for (myCount = 0, myIndex = 0; myIndex < strlen(theString); myIndex++) {
  967.         if (URLUtils_IsEncodableChar(theString[myIndex])) {
  968.             myEncodedStr[myCount + 0] = kURLEscapeCharacter;
  969.             myChar = (theString[myIndex] >> 4) & 0x0f;
  970.             myEncodedStr[myCount + 1] = myChar + ((myChar <= 9) ? '0' : ('A' - 10));
  971.             myChar = theString[myIndex] & 0x0f;
  972.             myEncodedStr[myCount + 2] = myChar + ((myChar <= 9) ? '0' : ('A' - 10));
  973.             myCount += 3;        
  974.         } else {
  975.             myEncodedStr[myCount] = theString[myIndex];
  976.             myCount++;        
  977.         }
  978.     }
  979.     
  980.     myEncodedStr[myCount] = '\0';
  981.     
  982. bail:
  983.     return(myEncodedStr);
  984. }
  985.  
  986.  
  987. //////////
  988. //
  989. // URLUtils_DecodeString 
  990. // Convert any encoded characters in the specified string into their unencoded versions.
  991. //
  992. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  993. //
  994. //////////
  995.  
  996. static char *URLUtils_DecodeString (char *theString)
  997. {
  998.     char        *myDecodedStr = NULL;    
  999.     char        myChar, myTemp1, myTemp2;
  1000.     short        myCount = 0;
  1001.     short        myIndex;
  1002.     short        myLength;
  1003.  
  1004.     if (theString == NULL)
  1005.         goto bail;
  1006.  
  1007.     // count the number of escape characters in the string
  1008.     for (myIndex = 0; myIndex < strlen(theString); myIndex++)
  1009.         if (theString[myIndex] == kURLEscapeCharacter)
  1010.             myCount++;
  1011.  
  1012.     // allocate a character string of the proper size;
  1013.     // each encoded character decreases the length of the original string by 2 bytes
  1014.     myLength = strlen(theString) + 1 - (myCount * 2);
  1015.     myDecodedStr = malloc(myLength);
  1016.     if (myDecodedStr == NULL)
  1017.         goto bail;
  1018.  
  1019.     // traverse the URL, decoding encoded characters as we go
  1020.     for (myCount = 0, myIndex = 0; myIndex < myLength; myIndex++) {
  1021.         if (theString[myCount] == kURLEscapeCharacter) {
  1022.         
  1023.             // make sure that any hex digits are uppercase
  1024.             myTemp1 = URLUtils_ToUppercase(theString[myCount + 1]);
  1025.             myTemp2 = URLUtils_ToUppercase(theString[myCount + 2]);
  1026.         
  1027.             myChar = ((myTemp1 - ((myTemp1 <= '9' ? '0' : 'A' - 10))) << 4) & 0xf0;
  1028.             myChar += (myTemp2 - ((myTemp2 <= '9' ? '0' : 'A' - 10))) & 0x0f;
  1029.             myDecodedStr[myIndex] = myChar;
  1030.             myCount += 3;
  1031.         } else {
  1032.             myDecodedStr[myIndex] = theString[myCount];
  1033.             myCount++;
  1034.         }
  1035.     }
  1036.     
  1037.     myDecodedStr[myLength] = '\0';
  1038.     
  1039. bail:
  1040.     return(myDecodedStr);
  1041. }
  1042.  
  1043.  
  1044. #endif    // ifndef __URLUtilities__